package com.graduation.project.service.process.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.graduation.project.entity.dto.DeleteFileDTO;
import com.graduation.project.entity.dto.UploadFileDTO;
import com.graduation.project.entity.dto.task.ListTaskDTO;
import com.graduation.project.entity.dto.UpdateStatusDTO;
import com.graduation.project.entity.other.LoginUser;
import com.graduation.project.entity.po.OpenReport;
import com.graduation.project.entity.vo.ListOpenReportVO;
import com.graduation.project.entity.vo.openReport.AuditMessageVO;
import com.graduation.project.enums.ResultCodeEnum;
import com.graduation.project.mapper.process.ListOpenReportMapper;
import com.graduation.project.mapper.process.OpenReportMapper;
import com.graduation.project.service.process.OpenReportService;
import com.graduation.project.service.process.ThesisService;
import com.graduation.project.utils.FileUtil;
import com.graduation.project.utils.ResultUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.util.HashMap;
import java.util.Map;

@Service
public class OpenReportServiceImpl extends ServiceImpl<OpenReportMapper, OpenReport> implements OpenReportService {

    @Autowired
    private OpenReportMapper openReportMapper;
    @Autowired
    private ListOpenReportMapper listOpenReportMapper;
    @Autowired
    private ThesisService thesisService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void createOpenReport(Long taskId) {
        // 判断数据库是否已存在此课题的开题报告记录
        OpenReport openReport = openReportMapper.selectOne(new LambdaQueryWrapper<OpenReport>().eq(OpenReport::getTaskId, taskId));
        if (ObjectUtil.isNotEmpty(openReport)) {
            throw new RuntimeException("课题开题报告已存在");
        }
        OpenReport insert = new OpenReport();
        insert.setTaskId(taskId);
        try {
            openReportMapper.insert(insert);
        } catch (Exception e) {
            throw new RuntimeException("创建开题报告失败");
        }
    }

    @Override
    public ResultUtil<?> listOpenReportByCondition(ListTaskDTO input) {
        IPage<ListOpenReportVO> page = new Page<>();
        page.setCurrent(input.getCurrentPage());
        page.setSize(input.getPageSize());
        IPage<ListOpenReportVO> data = listOpenReportMapper.listOpenReportByCondition(page, input);
        Map<String, Object> map = new HashMap<>();
        map.put("listOpenReportVo", data.getRecords());
        map.put("total", data.getTotal());
        return ResultUtil.Success(ResultCodeEnum.SUCCESS.getCode(), "查询成功", map);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultUtil<?> uploadOpenReportFile(UploadFileDTO input) {
        if (ObjectUtil.isEmpty(input.getFile())) {
            return ResultUtil.Failed(ResultCodeEnum.FILED.getCode(), "上传文件不能为空");
        }
        // 判断数据是否存在
        OpenReport openReport = openReportMapper.selectOne(new LambdaQueryWrapper<OpenReport>().eq(OpenReport::getId, input.getId()));
        if (ObjectUtil.isEmpty(openReport)) {
            return ResultUtil.Failed(ResultCodeEnum.FILED.getCode(), "数据不存在");
        }
        // 获取用户信息
        UsernamePasswordAuthenticationToken authenticationToken = (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
        LoginUser loginUser = (LoginUser) authenticationToken.getPrincipal();
        // 获取用户上传文件后缀，并通过uuid命名文件
        String fileName = input.getFile().getOriginalFilename();
        String suffix = fileName.substring(fileName.lastIndexOf("."));
        fileName = IdUtil.simpleUUID() + suffix;
        String filePath = "public/static/zyf_file/" + loginUser.getUser().getUserCode() + "/" + input.getFileType() + "/";
        openReport.setFilePath(filePath + fileName);
        try {
            // 保存到数据库（保存相对路径）
            openReportMapper.updateById(openReport);
            // 上传文件
            FileUtil.uploadFile(input.getFile(), filePath, fileName);
        }catch (Exception e) {
            throw new RuntimeException("上传失败");
        }
        return ResultUtil.Success(ResultCodeEnum.SUCCESS.getCode(), "上传成功");
    }

    @Override
    public ResultUtil<?> deleteOpenReportFile(DeleteFileDTO input) {
        // 判断数据是否存在
        OpenReport openReport = openReportMapper.selectOne(new LambdaQueryWrapper<OpenReport>().eq(OpenReport::getId, input.getId()));
        if (ObjectUtil.isEmpty(openReport)) {
            return ResultUtil.Failed(ResultCodeEnum.FILED.getCode(), "数据不存在");
        }
        // 清空file_path字段
        openReport.setFilePath("");
        // 还原审核状态
        openReport.setAuditStatus(0);
        openReport.setAuditIdea("");
        openReport.setDirectorAuditStatus(0);
        openReport.setDirectorAuditIdea("");
        try {
            openReportMapper.updateById(openReport);
        }catch (Exception e) {
            throw new RuntimeException("删除失败");
        }
        try {
            // 删除文件
            FileUtil.deleteFile(input.getFilePath());
        }catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
        return ResultUtil.Success(ResultCodeEnum.SUCCESS.getCode(), "删除成功");
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultUtil<?> teacherAuditOpenReport(UpdateStatusDTO input) {
        // 判断开题报告是否存在
        LambdaQueryWrapper<OpenReport> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(OpenReport::getId, input.getId());
        OpenReport openReport = openReportMapper.selectOne(lambdaQueryWrapper);
        if (ObjectUtil.isEmpty(openReport)) {
            throw new RuntimeException("开题报告不存在");
        }
        openReport.setAuditStatus(input.getStatus());
        openReport.setAuditIdea(input.getIdea());
        try {
            openReportMapper.updateById(openReport);
        }catch (Exception e) {
            throw new RuntimeException("审核失败");
        }
        return ResultUtil.Success(ResultCodeEnum.SUCCESS.getCode(), "审核成功");
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultUtil<?> directorAuditOpenReport(UpdateStatusDTO input) {
        // 判断开题报告是否存在
        LambdaQueryWrapper<OpenReport> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(OpenReport::getId, input.getId());
        OpenReport openReport = openReportMapper.selectOne(lambdaQueryWrapper);
        if (ObjectUtil.isEmpty(openReport)) {
            throw new RuntimeException("开题报告不存在");
        }
        openReport.setDirectorAuditStatus(input.getStatus());
        openReport.setDirectorAuditIdea(input.getIdea());
        try {
            openReportMapper.updateById(openReport);
            // 如果审核通过生成一条论文初稿数据
            if (input.getStatus().equals(1)) {
                thesisService.createThesis(openReport.getTaskId(), 0);
            }
        }catch (Exception e) {
            throw new RuntimeException("审核失败");
        }
        return ResultUtil.Success(ResultCodeEnum.SUCCESS.getCode(), "审核成功");
    }

    @Override
    public ResultUtil<?> getAuditMessage(Long id) {
        if (ObjectUtil.isEmpty(id)) {
            return ResultUtil.Failed(ResultCodeEnum.FILED.getCode(), "参数不能为空");
        }
        // 判断开题报告是否存在
        LambdaQueryWrapper<OpenReport> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(OpenReport::getId, id);
        OpenReport openReport = openReportMapper.selectOne(lambdaQueryWrapper);
        if (ObjectUtil.isEmpty(openReport)) {
            throw new RuntimeException("开题报告不存在");
        }
        AuditMessageVO output = new AuditMessageVO();
        BeanUtil.copyProperties(openReport, output);
        return ResultUtil.Success(ResultCodeEnum.SUCCESS.getCode(), "成功", output);
    }
}
